/*
 * MIT License
 *
 * Copyright (c) 2019 Mr.css
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package cn.seaboot.commons.reflect;

import cn.seaboot.commons.core.CommonUtils;
import cn.seaboot.commons.exception.ReflectException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 主要用于对象解析
 *
 * @author Mr.css
 * @version 2019/8/22 17:15
 */
public class ObjectUtils {
    private ObjectUtils() {
    }

    /**
     * 获取 type 的泛型，class 是无法获取泛型的
     *
     * @param type 类型
     * @return Type
     */
    @Nullable
    public static Type[] getGeneric(@NotNull Type type) {
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取 type 的泛型，class 是无法获取泛型的
     *
     * @param type 类型
     * @return Type
     */
    @Nullable
    public static Type getFirstGeneric(@NotNull Type type) {
        return getFirstGeneric(getGeneric(type));
    }

    /**
     * 获取参数的泛型
     *
     * @param parameter 参数
     * @return Type
     */
    @Nullable
    public static Type[] getGeneric(@NotNull Parameter parameter) {
        Type type = parameter.getParameterizedType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取参数的泛型
     *
     * @param parameter 参数
     * @return Type
     */
    @Nullable
    public static Type getFirstGeneric(@NotNull Parameter parameter) {
        return getFirstGeneric(getGeneric(parameter));
    }

    /**
     * 获取字段的泛型
     *
     * @param field 对象字段
     * @return Type
     */
    @Nullable
    public static Type[] getGeneric(@NotNull Field field) {
        Type type = field.getGenericType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取字段的泛型
     *
     * @param field 对象字段
     * @return Type
     */
    @Nullable
    public static Type getFirstGeneric(@NotNull Field field) {
        return getFirstGeneric(getGeneric(field));
    }

    /**
     * 获取某个接口的泛型，
     * 例如：A类继承自List，List用到的泛型数Integer，业务中需要获取List采用的泛型。
     * 此时：instance填A.class, targetClass填写List.class
     *
     * @param instance    对象实例/接口
     * @param targetClass 目标接口
     * @return Type
     */
    @Nullable
    public static Type[] getGeneric(@NotNull Class<?> instance, @NotNull Class<?> targetClass) {
        Type[] superclass = instance.getGenericInterfaces();
        for (Type type : superclass) {
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterized = (ParameterizedType) type;
                if (parameterized.getRawType().equals(targetClass)) {
                    return parameterized.getActualTypeArguments();
                }
            }
        }
        return null;
    }

    /**
     * 获取某个接口的泛型
     *
     * @param instance    对象实例/接口
     * @param targetClass 目标接口
     * @return Type
     */
    @Nullable
    public static Type getFirstGeneric(@NotNull Class<?> instance, @NotNull Class<?> targetClass) {
        return getFirstGeneric(getGeneric(instance, targetClass));
    }

    /**
     * 获取返回值泛型
     *
     * @param method -
     * @return type[]
     */
    @Nullable
    public static Type[] getReturnGeneric(@NotNull Method method) {
        Type type = method.getGenericReturnType();
        if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            return parameterizedType.getActualTypeArguments();
        }
        return null;
    }

    /**
     * 获取返回值泛型
     *
     * @param method -
     * @return type[]
     */
    @Nullable
    public static Type getFirstReturnGeneric(@NotNull Method method) {
        return getFirstGeneric(getReturnGeneric(method));
    }

    /**
     * 多数场合下，并不需要返回全部的泛型类型
     *
     * @return 第一个泛型
     */
    @Nullable
    public static Type getFirstGeneric(@Nullable Type[] types) {
        if (CommonUtils.isNotEmpty(types)) {
            return types[0];
        } else {
            return null;
        }
    }


    /**
     * 获取非空集合的泛型
     *
     * @param c 非空集合
     */
    public static Class<?> getCollectionGeneric(@NotNull Collection<?> c) {
        if (!c.isEmpty()) {
            return c.iterator().next().getClass();
        }
        return null;
    }

    /**
     * 获取非空数组的泛型
     *
     * @param o 非空数组
     */
    public static Class<?> getArrayGeneric(@NotNull Object o) {
        int len = Array.getLength(o);
        if (len > 0) {
            return Array.get(o, 0).getClass();
        }
        return null;
    }


    /**
     * 遍历每一个对象元素
     *
     * @param o 可能是数组、集合、对象中的一种
     */
    public static void eachElement(Object o, Consumer<Object> consumer) {
        if (o != null) {
            Class<?> clazz = o.getClass();
            if (Map.class.isAssignableFrom(clazz)) {
                return;
            }
            if (Collection.class.isAssignableFrom(clazz)) {
                Collection<?> c = (Collection<?>) o;
                if (!c.isEmpty()) {
                    c.forEach(consumer);
                }
            } else if (clazz.isArray()) {
                // array
                int len = Array.getLength(o);
                if (len > 0) {
                    for (int i = 0; i < len; i++) {
                        consumer.accept(Array.get(o, i));
                    }
                }
            } else {
                consumer.accept(o);
            }
        }
    }

    /**
     * 遍历每一个对象元素
     *
     * @param o 可能是数组、集合、对象中的一种
     * @return 转换之后的元素
     */
    public static <R> Object applyEachElement(Object o, Function<Object, R> function) {
        if (o == null) {
            return null;
        }
        Class<?> clazz = o.getClass();
        if (Map.class.isAssignableFrom(clazz)) {
            return null;
        }
        if (Collection.class.isAssignableFrom(clazz)) {
            Collection<?> c = (Collection<?>) o;
            if (c.isEmpty()) {
                return Collections.emptyList();
            } else {
                return c.stream().map(function).collect(Collectors.toList());
            }
        } else if (clazz.isArray()) {
            // array
            int len = Array.getLength(o);
            Object[] ret = new Object[len];
            if (len > 0) {
                for (int i = 0; i < len; i++) {
                    ret[i] = function.apply(Array.get(o, i));
                }
            }
            return ret;
        } else {
            return function.apply(o);
        }
    }

    /**
     * 复制所有非空字段
     * <p>
     * 做数据更新的时候，先查询旧数据，将新的数据逐个复制到旧的数据中，在Hibernate下会非常实用
     *
     * @param source -
     * @param target -
     */
    public static <T> T copyField(Object source, T target) {
        FieldAccess from = FieldAccess.create(source.getClass());
        FieldAccess to = FieldAccess.create(target.getClass());
        for (ObjectField property : to.getFields()) {
            property.setValue(target, from.getValue(source, property.getName()));
        }
        return target;
    }

    /**
     * 创建一个对象实例
     *
     * @return instance
     */
    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ReflectException("Create new instance failed：" + clazz, e);
        }
    }

    /**
     * 创建一个对象实例
     *
     * @return instance
     */
    public static Class<?> forName(@NotNull String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new ReflectException("Class not found：" + className, e);
        }
    }
}
